/**
 *
 * The MIT License
 *
 * Copyright (c) 2009 Ben Suter. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:

 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.

 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package org.macdadi.ks.client.components;

import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.core.client.GWT;
import com.google.gwt.http.client.URL;
import org.macdadi.core.client.domain.DataService;
import org.macdadi.core.client.domain.ValuedOption;
import org.macdadi.core.client.auth.AuthorizationException;

/**
 * @author Ben Suter <ben.suter@gmail.com>
 */
public class ValuesChart extends Composite
{
    protected final String CHART_URL_BASE = "http://chart.apis.google.com/chart?";
    public static final String CSS_CLASS = "macdadi-ValuesChart";
    protected HorizontalPanel chartPanel;
    protected String chartTitle = "Options ranked by Value";
    protected boolean showMessageIfNotAuthorized = true;

    public ValuesChart()
    {
        chartPanel = new HorizontalPanel();
        chartPanel.setWidth("100%");
        initWidget(chartPanel);
        setStyleName(CSS_CLASS);
    }

    public void clear()
    {
        chartPanel.clear();
    }
    
    public void populate(final int projectId, final String authToken)
    {

        DataService.App.getInstance().getOptionValues(projectId, authToken, new AsyncCallback()
        {
            public void onFailure(Throwable caught)
            {
                GWT.log("Failed to populate the values chart", caught);
                if (caught instanceof AuthorizationException && showMessageIfNotAuthorized) {
                    chartPanel.add(new HTML("Please login to view values"));
                }
            }

            public void onSuccess(Object result)
            {
                ValuedOption[] valuedOptions = (ValuedOption[]) result;
                drawChart(valuedOptions);
            }
        });

    }

    protected void drawChart(ValuedOption[] valuedOptions)
    {
        if ( valuedOptions.length == 0 ) {
            /* No data to display */
            chartPanel.add(new HTML("No data for display. Perhaps no options have been evaluated yet."));
            return;
        }

        // TODO: consider using the Google Visualization API for GWT
        // TODO: consider using a new client-side library, e.g. flot or gflot

        /* The following comments show the parameters used for a representative
         * Google Chart API chart of option values.
         */
        // http://chart.apis.google.com/chart?cht=bhs&chtt=Value%20per%20option%20wrt%20all%20goals%20weighted%20by%20prefs&chs=600x200&chd=t:-28,-27,11,2,-1&chds=-32,32&chco=bf2a2a&chxt=x,y&chxl=1:|Concrete%20Shear%20Wall%20First%20Floor%20Timber%20Above%20(3a)|Steel%20Braced%20Frame%20(2b)|Steel%20Moment%20Frame%20(2a)|Concrete%20Moment%20Frame%20(1b)|Concrete%20Shear%20Wall%20(1a)|0:|low%20value|zero|high%20value
        // http://chart.apis.google.com/chart?
        // cht=bhs
        // &chtt=Value%20per%20option%20wrt%20all%20goals%20weighted%20by%20prefs
        // &chs=600x200
        // &chd=t:-28,-27,11,2,-1
        // &chds=-32,32
        // &chco=bf2a2a
        // &chxt=x,y
        // &chxl=1:|Concrete%20Shear%20Wall%20First%20Floor%20Timber%20Above%20(3a)|Steel%20Braced%20Frame%20(2b)|Steel%20Moment%20Frame%20(2a)|Concrete%20Moment%20Frame%20(1b)|Concrete%20Shear%20Wall%20(1a)|0:|low%20value|zero|high%20value

        StringBuffer url = new StringBuffer();
        url.append(CHART_URL_BASE);
        url.append("cht=bhs"); // horizontal bar chart
        url.append("&chs=650x").append(50 + valuedOptions.length * 30); // size in pixels, height based on # of options
        url.append("&chco=bf2a2a"); // color is same as view, dark red
        url.append("&chtt=").append(URL.encodeComponent(chartTitle)); // title
        url.append("&chxt=x,y"); // two axes

        ValuedOption vo;
        double[] data = new double[valuedOptions.length];
        String[] labels = new String[valuedOptions.length];
        for (int i = 0; i < valuedOptions.length; i++) {
            vo = valuedOptions[i];
            data[i] = vo.getWeightedValue();
            labels[i] = vo.getName();
        }

        /* Balance negative and positive, e.g. &chds=-32,32 */
        double max = 0;
        double absVal;
        for (int i = 0; i < data.length; i++ ) {
            absVal = Math.abs(data[i]);
            if ( absVal > max )
                max = absVal;
        }
        max = max + 5; // leave a little space on either side of longest bar
        url.append("&chds=").append(-max).append(",").append(max);

        /* Set the data, e.g. &chd=t:-28,-27,11,2,-1 */
        url.append("&chd=t:");
        for (int i = 0; i < data.length; i++) {
            if ( i > 0 )
                url.append(",");

            url.append(data[i]);
        }

        /* Set the axis labels */
        // e.g. &chxl=1:|Concrete%20Shear%20Wall%20First%20Floor%20Timber%20Above%20(3a)|Steel%20Braced%20Frame%20(2b)|Steel%20Moment%20Frame%20(2a)|Concrete%20Moment%20Frame%20(1b)|Concrete%20Shear%20Wall%20(1a)  */
        url.append("&chxl=1:");
        /* Note: the first label is closest to the origin, but the first data bar is on top, so need to reverse the order of the labels here */
        for (int i = labels.length; i > 0; i--) {
            url.append("|").append(labels[i-1]);
        }
        url.append("|0:|low%20value|zero|high%20value"); // the x-axis labels

        HTML chart = new HTML("<img src=\"" + url.toString() + "\" title=\"Values chart\" />");
        chartPanel.add(chart);

        //GWT.log(url.toString(), null);  // good for debugging and modifying the chart appearance
    }

    public void setChartTitle(String title)
    {
        this.chartTitle = title;
    }

    public String getChartTitle()
    {
        return chartTitle;
    }
        
    public boolean isShowMessageIfNotAuthorized() {
        return showMessageIfNotAuthorized;
    }

    public void setShowMessageIfNotAuthorized(boolean showMessageIfNotAuthorized) {
        this.showMessageIfNotAuthorized = showMessageIfNotAuthorized;
    }
}
